package ai.neuralnet.builders;

import ai.neuralnet.NNBuilder;
import ai.neuralnet.NeuralNetwork;
import ai.neuralnet.TNeuron;

import java.util.ArrayList;

public class SimpleBuilder<N extends TNeuron, NN extends NeuralNetwork<N>> extends NNBuilder<N, NN>
{


    protected SimpleBuilder(Class<N> nClass, Class<NN> nnClass)
    {
        super(nClass, nnClass);
    }

    @Override
    public NN build()
    {
        return makeIntermediate();
    }

    private NN makeIntermediate()
    {
        NN network = makeNeuralNetwork();

        N[] inputs = makeNeuronArray(25);

        for (int i = 0; i < 25; i++)
        {
            inputs[i] = makeNeuron(1);
            inputs[i].setIsInputNeuron(true);
        }

        network.setInputNeurons(inputs);

        ArrayList<N> pitchGroup = new ArrayList<N>();

        for (int i = 0; i < 4; i++)
        {
            N pitch = makeNeuron(4);
            pitch.addInputNeuron(inputs[0]);
            inputs[0].addOutputNeuron(pitch);
            for (int j = 1 + i * 3; j < 1 + (i + 1) * 3; j++)
            {
                pitch.addInputNeuron(inputs[j]);
                inputs[j].addOutputNeuron(pitch);
            }
            pitchGroup.add(pitch);
        }

        ArrayList<N> timbreGroup = new ArrayList<N>();

        for (int i = 0; i < 4; i++)
        {
            N timbre = makeNeuron(4);
            timbre.addInputNeuron(inputs[0]);
            inputs[0].addOutputNeuron(timbre);
            for (int j = 13 + i * 3; j < 13 + (i + 1) * 3; j++)
            {
                timbre.addInputNeuron(inputs[j]);
                inputs[j].addOutputNeuron(timbre);
            }
            timbreGroup.add(timbre);
        }

        network.addHiddenNeuron(pitchGroup);
        network.addHiddenNeuron(timbreGroup);

        N[] outputs = makeNeuronArray(5);
        for (int i = 0; i < 5; i++)
        {
            outputs[i] = makeNeuron(8);
            for (N n : pitchGroup)
            {
                outputs[i].addInputNeuron(n);
                n.addOutputNeuron(outputs[i]);
            }

            for (N n : timbreGroup)
            {
                outputs[i].addInputNeuron(n);
                n.addOutputNeuron(outputs[i]);
            }
        }

        network.setOutputNeurons(outputs);

        return network;
    }


    private NN makeTiny()
    {
        NN network = makeNeuralNetwork();

        N[] inputs = makeNeuronArray(25);

        for (int i = 0; i < 25; i++)
        {
            inputs[i] = makeNeuron(1);
            inputs[i].setIsInputNeuron(true);
        }

        network.setInputNeurons(inputs);

        N pitch = makeNeuron(12);

        for (int i = 1; i < 13; i++)
        {
            pitch.addInputNeuron(inputs[i]);
            inputs[i].addOutputNeuron(pitch);
        }

        N timbre = makeNeuron(12);

        for (int i = 13; i < 25; i++)
        {
            timbre.addInputNeuron(inputs[i]);
            inputs[i].addOutputNeuron(timbre);
        }

        network.addHiddenNeuron(pitch);
        network.addHiddenNeuron(timbre);


        ArrayList<N> outputs = new ArrayList<N>();
        for (int i = 0; i < 5; i++)
        {
            N n = makeNeuron(3);
            outputs.add(n);
            n.addInputNeuron(inputs[0]);
            n.addInputNeuron(pitch);
            n.addInputNeuron(timbre);

        }

        pitch.addOutputNeuron(outputs);
        timbre.addOutputNeuron(outputs);
        inputs[0].addOutputNeuron(outputs);

        N[] out = makeNeuronArray(5);

        outputs.toArray(out);

        network.setOutputNeurons(out);

        return network;
    }
}
